﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using myControls = Diplom.Controls;
using Diplom.NumericArrays;
using Diplom.Utilities;
using Diplom.Graphics.D2D;
using Diplom.Forms;

namespace Diplom
{
    public partial class ArrayDesigner : Form
    {
        private List<myControls.ArrayInfo> arrayInfoControls;
        private List<Numeric1DArray> arrayNumeric1D;
        private Dictionary<int, Numeric1DArray> arrayInfoAction = new Dictionary<int, Numeric1DArray>();

        public ArrayDesigner()
        {
            InitializeComponent();
        }

        private void ArrayDesigner_Load(object sender, EventArgs e)
        {
            arrayInfoControls = new List<Diplom.Controls.ArrayInfo>();
            arrayNumeric1D = new List<Numeric1DArray>();

            System.Threading.Thread.CurrentThread.CurrentCulture =
                System.Globalization.CultureInfo.InvariantCulture;

            selectOperation1.SelectedIndex = 0;
            selectOperation2.SelectedIndex = 0;
        }

        private void ArrayDesigner_Paint(object sender, PaintEventArgs e)
        {
            if (tabControl1.SelectedIndex == 0)
            {
                if (arrayInfoControls.Count > 0)
                {
                    panel1.Width = 285 * arrayInfoControls.Count;
                    pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);

                    Image img = pictureBox1.Image;
                    System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(img);
                    DrawStyle style = new DrawStyle(Color.Blue, new Point(0, 0), new Point(1, 1), Color.Red, Color.Red);

                    for (int i = 0; i < arrayNumeric1D.Count; i++)
                    {
                        Numeric1DArray ar = arrayNumeric1D[i];
                        D2DVisualizer.DrawGraphic(ref gr,
                            ref ar,
                            new RectangleF(i * arrayInfoControls[0].Width, 0,
                                arrayInfoControls[0].Width, pictureBox1.Height), style);
                    }

                    pictureBox1.Image = img;
                }
                else
                {
                    panel1.Width = 285;
                    pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
                }
            }
            else
            {
                pictureBox2.Image = new Bitmap(pictureBox2.Width, pictureBox2.Height);
                                
                if (arrayNumeric1D != null && arrayNumeric1D.Count > 0)
                {
                    System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(pictureBox2.Image);
                    graphics.Clear(Color.White);
                    DrawStyle style = new DrawStyle(Color.Blue, new Point(0, 0), new Point(1, 1), Color.Red, Color.Red);

                    Numeric1DArray ar = arrayNumeric1D[0];
                    D2DVisualizer.DrawGraphic(ref graphics,
                        ref ar,
                        new RectangleF(0, 0,
                            pictureBox2.Width, pictureBox2.Height), style);
                }
            }
        }

        private void buttonAddNewArrayInfo_Click(object sender, EventArgs e)
        {
            int left;
            if (arrayInfoControls.Count == 0)
            {
                left = 0;
            }
            else
            {
                left = arrayInfoControls[0].Width * arrayInfoControls.Count;
            }

            myControls.ArrayInfo arInfo = new Diplom.Controls.ArrayInfo();
            arInfo.Name = "arInfo" + (arrayInfoControls.Count + 1).ToString();
            arInfo.Location = new Point(left, 0);
            arInfo.buttonDeleteArray.Text = (arrayInfoControls.Count + 1).ToString();
            arInfo.buttonDeleteArray.Click += new EventHandler(buttonDeleteArray_Click);
            arInfo.txtBoxAmplitude.TextChanged += new EventHandler(ReCalculateData);
            arInfo.txtBoxFrequence.TextChanged += new EventHandler(ReCalculateData);
            arInfo.txtBoxInterval.TextChanged += new EventHandler(ReCalculateData);
            arInfo.txtBoxLength.TextChanged += new EventHandler(ReCalculateData);
            arInfo.txtBoxPhase.TextChanged += new EventHandler(ReCalculateData);
            arInfo.comboBoxSelFunc.SelectedIndexChanged += new EventHandler(ReCalculateData);
            arInfo.buttonAction.Click += new EventHandler(buttonAction_Click);
            arInfo.buttonActionRemove.Enabled = false;
            arInfo.buttonActionRemove.Click += new EventHandler(buttonActionRemove_Click);
            controlsContainer.Controls.Add(arInfo);

            arrayInfoControls.Add(arInfo);

            Numeric1DArray ar = new Numeric1DArray();
            Function function = Function.Cos;
            int length = Int32.Parse(arInfo.txtBoxLength.Text);
            double frequency = double.Parse(arInfo.txtBoxFrequence.Text);
            string[] interval = arInfo.txtBoxInterval.Text.Split(new String[] { " ", ";" }, StringSplitOptions.RemoveEmptyEntries);
            double phase = double.Parse(arInfo.txtBoxPhase.Text);
            double begin = double.Parse(interval[0]);
            double end = double.Parse(interval[1]);
            double amplitude = double.Parse(arInfo.txtBoxAmplitude.Text);
            Parameters parameters = new Parameters(length, frequency, phase, amplitude, begin, end);
            ArrayGenerator.Generate(function,
                ref ar, parameters);

            arrayNumeric1D.Add(ar);

            controlsContainer.Width = 285 * arrayInfoControls.Count;
        }

        private void buttonDeleteArray_Click(object sender, EventArgs e)
        {
            Button but = (Button)sender;

            foreach (Control control in controlsContainer.Controls)
            {
                if (control.Name == "arInfo" + but.Text)
                {
                    controlsContainer.Controls.Remove(control);
                    arrayInfoControls.Remove((myControls.ArrayInfo)control);
                    break;
                }
            }
            for (int i = 0; i < controlsContainer.Controls.Count; i++)
            {
                myControls.ArrayInfo arInfo = controlsContainer.Controls[i] as myControls.ArrayInfo;
                if (arInfo != null)
                {
                    arInfo.Location = new Point(arInfo.Width * i, 0);
                    arInfo.Name = "arInfo" + (i + 1).ToString();
                    arInfo.buttonDeleteArray.Text = (i + 1).ToString();

                    arrayInfoControls[i].Location = new Point(arInfo.Width * i, 0);
                    arrayInfoControls[i].Name = "arInfo" + (i + 1).ToString();
                    arrayInfoControls[i].buttonDeleteArray.Text = (i + 1).ToString();
                }
            }
            arrayNumeric1D.RemoveAt(int.Parse(but.Text) - 1);
            if (arrayInfoControls.Count > 0)
            {
                controlsContainer.Width = 285 * arrayInfoControls.Count;
            }
            this.Refresh();
        }

        private void buttonAction_Click(object sender, EventArgs e)
        {
            myControls.ArrayInfo arInfo = (myControls.ArrayInfo)((Control)sender).Parent;

            int index = int.Parse(arInfo.buttonDeleteArray.Text) - 1;
            string action = arInfo.selectAction.SelectedItem.ToString();

            ArrayActionDesigner arrayActionDesigner = new ArrayActionDesigner(arInfo.txtBoxInterval.Text,
                arInfo.txtBoxLength.Text);
            if (arrayActionDesigner.ShowDialog() == DialogResult.OK)
            {
                Numeric1DArray tmpArray1 = arrayActionDesigner.GetArray();
                Numeric1DArray tmpArray2 = new Numeric1DArray(arrayNumeric1D[index]);
                switch (action)
                {
                    case "+":
                        {
                            ArrayGenerator.SumArrays(ref tmpArray2, ref tmpArray1, 0);
                        } break;
                    case "-":
                        {
                            ArrayGenerator.DiffArrays(ref tmpArray2, ref tmpArray1, 0);
                        } break;
                    case "*":
                        {
                            ArrayGenerator.MultArrays(ref tmpArray2, ref tmpArray1, 0);
                        } break;
                    default:
                        {
                            return;
                        }
                }
                arrayInfoAction[index] = new Numeric1DArray(arrayNumeric1D[index]);
                arrayNumeric1D[index] = tmpArray2;
            }
            arInfo.buttonActionRemove.Enabled = true;
            this.Refresh();
        }

        private void ReCalculateData(object sender, EventArgs e)
        {
            myControls.ArrayInfo arInfo = (myControls.ArrayInfo)((Control)sender).Parent.Parent;

            Numeric1DArray ar = new Numeric1DArray();
            
            Function function;
            switch (arInfo.comboBoxSelFunc.Text)
            {
                case "Noise":
                    {
                        function = Function.Noise;
                    } break;
                case "Sin":
                    {
                        function = Function.Sin;
                    } break;
                case "Cos":
                    {
                        function = Function.Cos;
                    } break;
                case "Ln":
                    {
                        function = Function.Ln;
                    } break;
                case "Exp":
                    {
                        function = Function.Exp;
                    } break;
                case "Dirac":
                    {
                        function = Function.Dirac;
                    } break;
                case "Heaviside":
                    {
                        function = Function.Heaviside;
                    } break;
                case "CorrelationNoise":
                    {
                        function = Function.CorrelationNoise;
                    } break;
                default:
                    {
                        errorLabel.Text = "Unknown function";
                        return;
                    }
                    
            }
            int length;
            try
            {
                length = Int32.Parse(arInfo.txtBoxLength.Text);
                if (length < 2)
                    throw new Exception();
            }
            catch
            {
                errorLabel.Text = "Error in parsing Length field";
                return;
            }

            double frequency;
            try
            {
                frequency = double.Parse(arInfo.txtBoxFrequence.Text);
            }
            catch
            {
                errorLabel.Text = "Error in parsing Frequency field";
                return;
            }
            
            double phase;
            try
            {
                phase = double.Parse(arInfo.txtBoxPhase.Text);
            }
            catch
            {
                errorLabel.Text = "Error in parsing Phase field";
                return;
            }

            string[] interval = arInfo.txtBoxInterval.Text.Split(new String[] { " ", ";" }, StringSplitOptions.RemoveEmptyEntries);
            double begin;
            double end;
            try
            {
                begin = double.Parse(interval[0]);
                end = double.Parse(interval[1]);
            }
            catch
            {
                errorLabel.Text = "Error in parsing Interval field";
                return;
            }

            double amplitude;
            try
            {
                amplitude = double.Parse(arInfo.txtBoxAmplitude.Text);
                if (amplitude < 1e-6) throw new Exception();
            }
            catch
            {
                errorLabel.Text = "Error in parsing Amplitude field";
                return;
            }

            Parameters parameters = new Parameters(length, frequency, phase, amplitude, begin, end);
            ArrayGenerator.Generate(function,
                ref ar, parameters);
            
            arrayNumeric1D[int.Parse(arInfo.buttonDeleteArray.Text) - 1] = new Numeric1DArray(ar);

            errorLabel.Text = "";
            this.Refresh();
        }

        private void buttonActionRemove_Click(object sender, EventArgs e)
        {
            myControls.ArrayInfo arInfo = (myControls.ArrayInfo)((Control)sender).Parent;

            int index = int.Parse(arInfo.buttonDeleteArray.Text) - 1;
            if (arrayInfoAction.ContainsKey(index))
            {
                if (MessageBox.Show("Вы действительно хотите отменить действие?", "Information", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
                {
                    arrayNumeric1D[index] = new Numeric1DArray(arrayInfoAction[index]);
                    arrayInfoAction.Remove(index);
                }
            }

            arInfo.buttonActionRemove.Enabled = false;

            this.Refresh();
        }

        public Numeric1DArray Array
        {
            get
            {
                if (tabControl1.SelectedIndex == 0)
                {
                    Numeric1DArray fullArray = new Numeric1DArray(0);
                    for (int i = 0; i < arrayNumeric1D.Count; i++)
                    {
                        Numeric1DArray tmpArray = arrayNumeric1D[i];
                        fullArray = fullArray.Concat(ref tmpArray);
                    }
                    //fullArray.TimeMin = 1;
                    //fullArray.TimeMax = fullArray.Length;
                    return fullArray;
                }
                else
                {
                    if (arrayNumeric1D != null && arrayNumeric1D.Count > 0)
                    {
                        //arrayNumeric1D[0].TimeMin = 1;
                        //arrayNumeric1D[0].TimeMax = arrayNumeric1D[0].Length;
                        return arrayNumeric1D[0];
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            Numeric1DArray fullArray = new Numeric1DArray(0);
            for (int i = 0; i < arrayNumeric1D.Count; i++)
            {
                Numeric1DArray tmpArray = arrayNumeric1D[i];
                fullArray = fullArray.Concat(ref tmpArray);
            }
            if (fullArray.Length > 0)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Text files (*.txt,*.dat*,*.in,*.out)|*.txt;*.dat;*.in;*.out";
                saveFileDialog.InitialDirectory = System.Environment.CurrentDirectory;
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    if (string.IsNullOrEmpty(saveFileDialog.FileName))
                    {
                        return;
                    }
                    ArrayGenerator.SaveArray(ref fullArray, saveFileDialog.FileName);
                }
            }
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl1.SelectedIndex == 0)
            {
                buttonAddNewArrayInfo.Enabled = true;
            }
            else
            {
                buttonAddNewArrayInfo.Enabled = false;
            }
        }

        private void browseButon1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
            openFileDialog.Filter = "Text files (*.txt,*.dat*,*.in,*.out)|*.txt;*.dat;*.in;*.out";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                if (string.IsNullOrEmpty(openFileDialog.FileName)) { return; }

                path1.Text = openFileDialog.FileName;
                loadButton1_Click(sender, e);
            }
        }

        private void loadButton1_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(path1.Text))
            {
                MessageBox.Show("Path is empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path1.Focus();
                return;
            }
            if (!System.IO.File.Exists(path1.Text))
            {
                MessageBox.Show("File not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path1.Focus();
                return;
            }

            arrayNumeric1D = new List<Numeric1DArray>();
            Numeric1DArray array = new Numeric1DArray();
            Diplom.Utilities.ArrayGenerator.Generate(path1.Text, ref array);
            arrayNumeric1D.Add(array);

            this.Refresh();

            selectOperation1.Enabled = true;
            path2.Enabled = true;
            browseButon2.Enabled = true;
            loadButton2.Enabled = true;

            selectOperation2.Enabled = false;
            path3.Enabled = false;
            browseButon3.Enabled = false;
            loadButton3.Enabled = false;
        }

        private void loadButton2_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(path2.Text))
            {
                MessageBox.Show("Path is empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path2.Focus();
                return;
            }
            if (!System.IO.File.Exists(path2.Text))
            {
                MessageBox.Show("File not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path2.Focus();
                return;
            }

            Numeric1DArray tempArray1 = new Numeric1DArray();
            Diplom.Utilities.ArrayGenerator.Generate(path1.Text, ref tempArray1);

            Numeric1DArray tempArray2 = new Numeric1DArray();
            Diplom.Utilities.ArrayGenerator.Generate(path2.Text, ref tempArray2);
                        
            switch (selectOperation1.SelectedIndex)
            {
                case 0: // +
                    {
                        ArrayGenerator.SumArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 1: // -
                    {
                        ArrayGenerator.DiffArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 2: // *
                    {
                        ArrayGenerator.MultArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
            }
            arrayNumeric1D[0] = new Numeric1DArray(tempArray1);

            this.Refresh();

            selectOperation2.Enabled = true;
            path3.Enabled = true;
            browseButon3.Enabled = true;
            loadButton3.Enabled = true;
        }

        private void browseButon2_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
            openFileDialog.Filter = "Text files (*.txt,*.dat*,*.in,*.out)|*.txt;*.dat;*.in;*.out";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                if (string.IsNullOrEmpty(openFileDialog.FileName)) { return; }

                path2.Text = openFileDialog.FileName;
                loadButton2_Click(sender, e);
            }
        }

        private void browseButon3_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
            openFileDialog.Filter = "Text files (*.txt,*.dat*,*.in,*.out)|*.txt;*.dat;*.in;*.out";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                if (string.IsNullOrEmpty(openFileDialog.FileName)) { return; }

                path3.Text = openFileDialog.FileName;
                loadButton3_Click(sender, e);
            }
        }

        private void loadButton3_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(path3.Text))
            {
                MessageBox.Show("Path is empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path3.Focus();
                return;
            }
            if (!System.IO.File.Exists(path3.Text))
            {
                MessageBox.Show("File not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                path3.Focus();
                return;
            }

            Numeric1DArray tempArray1 = new Numeric1DArray();
            Diplom.Utilities.ArrayGenerator.Generate(path1.Text, ref tempArray1);

            Numeric1DArray tempArray2 = new Numeric1DArray();
            Diplom.Utilities.ArrayGenerator.Generate(path2.Text, ref tempArray2);

            switch (selectOperation1.SelectedIndex)
            {
                case 0: // +
                    {
                        ArrayGenerator.SumArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 1: // -
                    {
                        ArrayGenerator.DiffArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 2: // *
                    {
                        ArrayGenerator.MultArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
            }

            tempArray2 = new Numeric1DArray();
            ArrayGenerator.Generate(path3.Text, ref tempArray2);

            switch (selectOperation2.SelectedIndex)
            {
                case 0: // +
                    {
                        ArrayGenerator.SumArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 1: // -
                    {
                        ArrayGenerator.DiffArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
                case 2: // *
                    {
                        ArrayGenerator.MultArrays(ref tempArray1, ref tempArray2, 0);
                    } break;
            }
            arrayNumeric1D[0] = new Numeric1DArray(tempArray1);

            this.Refresh();
        }
    }
}